﻿using Bnbjoy.Business.Abstract;
using Bnbjoy.Business.Common;
using Bnbjoy.Business.Model.Dashboard;
using Bnbjoy.Business.Model.RoomType;
using Bnbjoy.Domain.Abstract;
using Bnbjoy.Domain.Entities;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bnbjoy.Business.Concrete
{
    public class RoomTypeService : IRoomTypeService
    {
        IRoomTypeRepository _repository;

        public RoomTypeService(IRoomTypeRepository roomTypeRepository)
        {
            this._repository = roomTypeRepository;
        }

        public async Task<RoomTypeResponse> NewRoomType(RoomType roomType, IEnumerable<Room> rooms, CommonPrice commonPrice)
        {
            //插入新的房型
            bool insertSuccess = await _repository.InsertRoomType(roomType, rooms, commonPrice);

            //查询并返回该新建房型信息
            dynamic newRoomType = await _repository.FindRoomType(roomType.BnbId, roomType.RoomTypeName);

            RoomTypeResponse roomTypeResponse = new RoomTypeResponse();
            roomTypeResponse.roomType = new RoomType
            {
                RoomTypeId = newRoomType.RoomTypeId,
                Rank = newRoomType.RoomTypeRank,
                RoomTypeName = newRoomType.RoomTypeName,
                Notes = newRoomType.Notes,
                BnbId = newRoomType.BnbId,
            };

            roomTypeResponse.commonPrice = new CommonPrice
            {
                Id = newRoomType.CommonPriceId,
                InitPrice = newRoomType.InitPrice,
                MondayPrice = newRoomType.MondayPrice,
                TuesdayPrice = newRoomType.TuesdayPrice,
                WednesdayPrice = newRoomType.WednesdayPrice,
                ThursdayPrice = newRoomType.ThursdayPrice,
                FridayPrice = newRoomType.FridayPrice,
                SaturdayPrice = newRoomType.SaturdayPrice,
                SundayPrice = newRoomType.SundayPrice,
                RoomTypeId = newRoomType.RoomTypeId,
            };

            roomTypeResponse.rooms = new List<Room>();
            List<Room> roomList = new List<Room>();
            var roomsJson = JsonConvert.SerializeObject(newRoomType.Rooms);
            var roomsObjs = JsonConvert.DeserializeObject<dynamic>(roomsJson);
            foreach (var room in roomsObjs)
            {
                Room r = new Room()
                {
                    BnbId = roomType.BnbId,
                    Rank = room.RoomRank,
                    Enabled = room.Enabled,
                    RoomNumber = room.RoomNumber,
                    RoomId = room.RoomId,
                    RoomTypeId = roomType.RoomTypeId,
                };
                roomList.Add(r);
            }
            roomTypeResponse.rooms = roomList;

            return roomTypeResponse;
        }

        public async Task<QueryAllRoomTypesResponse> Catalog(string bnbId)
        {
            try
            {
                var result = await _repository.ListAllRoomTypes(bnbId);
                QueryAllRoomTypesResponse response = new QueryAllRoomTypesResponse();
                response.roomTypes = new List<RoomTypeResponse>();

                foreach (var roomType in result)
                {
                    RoomTypeResponse roomTypeResponse = new RoomTypeResponse();
                    roomTypeResponse.roomType = new RoomType
                    {
                        RoomTypeId = roomType.RoomTypeId,
                        Rank = roomType.RoomTypeRank,
                        RoomTypeName = roomType.RoomTypeName,
                        Notes = roomType.Notes,
                        BnbId = roomType.BnbId,
                    };

                    roomTypeResponse.commonPrice = new CommonPrice
                    {
                        Id = roomType.CommonPriceId,
                        InitPrice = roomType.InitPrice,
                        MondayPrice = roomType.MondayPrice,
                        TuesdayPrice = roomType.TuesdayPrice,
                        WednesdayPrice = roomType.WednesdayPrice,
                        ThursdayPrice = roomType.ThursdayPrice,
                        FridayPrice = roomType.FridayPrice,
                        SaturdayPrice = roomType.SaturdayPrice,
                        SundayPrice = roomType.SundayPrice,
                        RoomTypeId = roomType.RoomTypeId,
                    };

                    roomTypeResponse.rooms = new List<Room>();
                    List<Room> roomList = new List<Room>();
                    var roomsJson = JsonConvert.SerializeObject(roomType.Rooms);
                    var roomsObjs = JsonConvert.DeserializeObject<dynamic>(roomsJson);
                    foreach (var room in roomsObjs)
                    {
                        Room r = new Room()
                        {
                            BnbId = roomType.BnbId,
                            Rank = room.RoomRank,
                            Enabled = room.Enabled,
                            RoomNumber = room.RoomNumber,
                            RoomId = room.RoomId,
                            RoomTypeId = roomType.RoomTypeId,
                        };
                        roomList.Add(r);
                    }
                    roomTypeResponse.rooms = roomList;
                    response.roomTypes.Add(roomTypeResponse);
                }

                return response;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public async Task<bool> MoveUpRank(string bnbId, int currentRank)
        {
            bool result = await _repository.UpRank(bnbId, currentRank);
            return result;
        }

        public async Task<bool> MoveDownRank(string bnbId, int currentRank)
        {
            bool result = await _repository.DownRank(bnbId, currentRank);
            return result;
        }

        public async Task<bool> ModifyDailyPrice(DateTime fromDate, DateTime toDate, string roomTypeId, decimal price)
        {
            bool result = await _repository.UpdateDailyPrice(fromDate, toDate, roomTypeId, price);
            return result;
        }


        public async Task<SortedDictionary<int, decimal>> FetchRoomTypeDailyPrice(int year, int month, string roomTypeId)
        {
            try
            {
                SortedDictionary<int, decimal> priceDic = new SortedDictionary<int, decimal>();

                DateTime dateTime = DateTime.Parse(string.Format("{0}-{1}-01", year, month < 10 ? "0" + month.ToString() : month.ToString()));
                //取出每周默认价格
                CommonPrice commonPrice = await _repository.RetrieveCommonPrice(roomTypeId);
                //取出当月特定范围用户自定义价格
                List<DailyPrice> dailyPriceList = await _repository.ListDailyPrice(dateTime, roomTypeId);
                foreach (var dp in dailyPriceList)
                {
                    for (var date = dp.FromDate; date.Date <= dp.ToDate; date = date.AddDays(1))
                    {
                        priceDic.Add(date.Day, dp.Price);
                    }
                }

                int days = DateTime.DaysInMonth(year, month);
                for (int day = 1; day <= days; day++)
                {
                    if (!priceDic.Keys.Contains(day))
                    {
                        DateTime tempDt = new DateTime(year, month, day);
                        int dayofWeek = ((int)tempDt.DayOfWeek == 0) ? 7 : (int)tempDt.DayOfWeek;
                        switch (dayofWeek)
                        {
                            case 1: priceDic.Add(day, commonPrice.MondayPrice); break;
                            case 2: priceDic.Add(day, commonPrice.TuesdayPrice); break;
                            case 3: priceDic.Add(day, commonPrice.WednesdayPrice); break;
                            case 4: priceDic.Add(day, commonPrice.ThursdayPrice); break;
                            case 5: priceDic.Add(day, commonPrice.FridayPrice); break;
                            case 6: priceDic.Add(day, commonPrice.SaturdayPrice); break;
                            case 7: priceDic.Add(day, commonPrice.SundayPrice); break;
                        }
                    }
                }

                return priceDic;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public async Task<SortedDictionary<string, decimal>> FetchCustomRoomTypeDailyPrice(DateTime fromTime, DateTime toTime, string roomTypeId)
        {
            try
            {
                SortedDictionary<string, decimal> priceDic = new SortedDictionary<string, decimal>();
                SortedDictionary<string, decimal> resultDic = new SortedDictionary<string, decimal>();

                //取出每周默认价格
                CommonPrice commonPrice = await _repository.RetrieveCommonPrice(roomTypeId);
                //取出当月特定范围用户自定义价格
                List<DailyPrice> dailyPriceList = await _repository.ListDailyPrice(fromTime, toTime, roomTypeId);
                foreach (var dp in dailyPriceList)
                {
                    for (var date = dp.FromDate; date.Date <= dp.ToDate; date = date.AddDays(1))
                    {
                        priceDic.Add(date.ToString("yyyy-MM-dd"), dp.Price);
                    }
                }

                for (var date = fromTime; date < toTime; date = date.AddDays(1))
                {
                    var dateStr = date.ToString("yyyy-MM-dd");
                    if (!priceDic.Keys.Contains(dateStr))
                    {
                        int dayofWeek = ((int)date.DayOfWeek == 0) ? 7 : (int)date.DayOfWeek;
                        switch (dayofWeek)
                        {
                            case 1: resultDic.Add(dateStr, commonPrice.MondayPrice); break;
                            case 2: resultDic.Add(dateStr, commonPrice.TuesdayPrice); break;
                            case 3: resultDic.Add(dateStr, commonPrice.WednesdayPrice); break;
                            case 4: resultDic.Add(dateStr, commonPrice.ThursdayPrice); break;
                            case 5: resultDic.Add(dateStr, commonPrice.FridayPrice); break;
                            case 6: resultDic.Add(dateStr, commonPrice.SaturdayPrice); break;
                            case 7: resultDic.Add(dateStr, commonPrice.SundayPrice); break;
                        }
                    }
                    else
                    {
                        resultDic.Add(dateStr, priceDic[dateStr]);
                    }
                }

                return resultDic;
            }
            catch (Exception ex)
            {
                return null;
            }
        }


        public async Task<Dictionary<string, SortedDictionary<string, decimal>>> FetchAllRoomTypeDailyPrice(DateTime fromTime, DateTime toTime, string bnbId)
        {
            try
            {
                Dictionary<string, SortedDictionary<string, decimal>> resultDic = new Dictionary<string, SortedDictionary<string, decimal>>();

                //取出每周默认价格
                List<CommonPrice> commonPriceList = await _repository.RetrieveCommonPriceByBnbId(bnbId);
                //取出当月特定范围用户自定义价格
                List<DailyPrice> dailyPriceList = await _repository.ListDailyPriceByBnbId(fromTime, toTime, bnbId);

                //初始化结果字典
                foreach (var cpl in commonPriceList)
                {
                    resultDic.Add(cpl.RoomTypeId, new SortedDictionary<string, decimal>());
                }

                //得到用户自定义的时间房价
                foreach (var dp in dailyPriceList)
                {
                    string roomTypeId = dp.RoomTypeId;
                    SortedDictionary<string, decimal> priceDic = new SortedDictionary<string, decimal>();

                    if (!resultDic.Keys.Contains(roomTypeId))
                    {
                        for (var date = dp.FromDate; date.Date <= dp.ToDate; date = date.AddDays(1))
                        {
                            priceDic.Add(date.ToString("yyyy-MM-dd"), dp.Price);
                        }

                        resultDic.Add(roomTypeId, priceDic);
                    }
                    else
                    {
                        var existedPriceDic = resultDic[roomTypeId];
                        for (var date = dp.FromDate; date.Date <= dp.ToDate; date = date.AddDays(1))
                        {
                            existedPriceDic.Add(date.ToString("yyyy-MM-dd"), dp.Price);
                        }
                    }
                }

                //设置通用的房价
                foreach (var r in resultDic)
                {
                    var tempDic = r.Value;
                    for (var date = fromTime; date <= toTime; date = date.AddDays(1))
                    {
                        var dateStr = date.ToString("yyyy-MM-dd");
                        if (!tempDic.Keys.Contains(dateStr))
                        {
                            int dayofWeek = ((int)date.DayOfWeek == 0) ? 7 : (int)date.DayOfWeek;
                            var commonPrice = commonPriceList.Where(c => c.RoomTypeId == r.Key).FirstOrDefault();
                            switch (dayofWeek)
                            {
                                case 1: tempDic.Add(dateStr, commonPrice.MondayPrice); break;
                                case 2: tempDic.Add(dateStr, commonPrice.TuesdayPrice); break;
                                case 3: tempDic.Add(dateStr, commonPrice.WednesdayPrice); break;
                                case 4: tempDic.Add(dateStr, commonPrice.ThursdayPrice); break;
                                case 5: tempDic.Add(dateStr, commonPrice.FridayPrice); break;
                                case 6: tempDic.Add(dateStr, commonPrice.SaturdayPrice); break;
                                case 7: tempDic.Add(dateStr, commonPrice.SundayPrice); break;
                            }
                        }
                    }
                }

                return resultDic;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public async Task<List<RoomsBasicInfoModel>> FetchAllBasicRoomsInfo(DateTime fromTime, DateTime toTime, string bnbId)
        {
            try
            {
                Dictionary<string, SortedDictionary<string, decimal>> allRoomTypeDailyPrices = await FetchAllRoomTypeDailyPrice(fromTime, toTime, bnbId);
                var basicRoomsInfo = await _repository.ListBasicRoomsInfo(fromTime, toTime, bnbId);

                var aggregate = basicRoomsInfo.GroupBy(x => x.RoomId).Select(group => new
                {
                    RoomInfo = group.Select(n => new RoomsBasicInfoModel
                    {
                        RoomId = n.RoomId,
                        RoomNumber = n.RoomNumber,
                        RoomTypeId = n.RoomTypeId,
                        RoomTypeName = n.RoomTypeName,
                        DailyPrice = allRoomTypeDailyPrices[Convert.ToString(n.RoomTypeId)]
                    }).First(),
                    Orders = group.Select(n => new BasicOrderModel
                    {
                        OrderId = n.OrderId,
                        FromDate = n.FromDate,
                        ToDate = n.ToDate,
                        RoomStatus = n.RoomStatus,
                        ReserverUser = n.ReserverUser,
                        RoomId = n.RoomId
                    }).ToList()
                }).ToList();

                if (aggregate != null)
                {
                    List<RoomsBasicInfoModel> roomsInfoList = new List<RoomsBasicInfoModel>();
                    foreach (var a in aggregate) 
                    {
                        RoomsBasicInfoModel r = new RoomsBasicInfoModel()
                        {
                            RoomId = a.RoomInfo.RoomId,
                            RoomNumber = a.RoomInfo.RoomNumber,
                            RoomTypeId = a.RoomInfo.RoomTypeId,
                            RoomTypeName = a.RoomInfo.RoomTypeName,
                            DailyPrice = a.RoomInfo.DailyPrice,
                            OrderModels = a.Orders
                        };
                        roomsInfoList.Add(r);
                    }

                    return roomsInfoList;
                }

                return null;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public void Dispose()
        {

        }
    }
}
